//
//  ViewController.m
//  keyboardtest
//
//  Created by  JasonLee on 2021/12/30.
//

#import "ViewController.h"
#import <Carbon/Carbon.h>
#include <sys/sysctl.h>
#include <sys/syscall.h>
#import <libproc.h>
#import <unistd.h>
#import <CommonCrypto/CommonCryptor.h>
#import <SystemConfiguration/SystemConfiguration.h>
#include <sys/vnode.h>
#include <sys/attr.h>
#include <pwd.h>
#include <dlfcn.h>
#import "TJJPastebpard.h"
//#import <HIToolbox/Events.h>
NSString* getProcessPath(pid_t pid)
{
    //task path
    NSString* processPath = nil;
    char pathBuffer[PROC_PIDPATHINFO_MAXSIZE] = {0};
    int status = -1;
    int mib[3] = {CTL_KERN, 0, 0};
    unsigned long systemMaxArgs = 0;
    char* taskArgs = NULL;
    size_t size = 0;

    status = proc_pidpath(pid, pathBuffer, sizeof(pathBuffer));
    if(0 != status) {
        processPath = [NSString stringWithUTF8String:pathBuffer];
    } else {
        mib[1] = KERN_ARGMAX;
        size = sizeof(systemMaxArgs);

        if(-1 == sysctl(mib, 2, &systemMaxArgs, &size, NULL, 0)) {
            goto end;
        }

        taskArgs = (char *)malloc(systemMaxArgs);
        if(NULL == taskArgs) {
            goto end;
        }

        mib[1] = KERN_PROCARGS2;
        mib[2] = pid;
        size = (size_t)systemMaxArgs;
        
        if((-1 == sysctl(mib, 3, taskArgs, &size, NULL, 0)) ||
           (size <= sizeof(int))) {
            goto end;
        }

        processPath = [NSString stringWithUTF8String:taskArgs + sizeof(int)];
    }
    
end:
    if(NULL != taskArgs) {
        free(taskArgs);
        taskArgs = NULL;
    }
    return processPath;
}

NSArray *getProcessList(void)
{
    int                 err = 0;
    size_t              count = 0;
    struct kinfo_proc   *list = NULL;
    static const int    name[] = { CTL_KERN, KERN_PROC, KERN_PROC_ALL, 0 };
    size_t              size = 0;
    NSArray             *ret = nil;
    NSMutableArray      *processes;
    
    // first get list size
    err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, NULL, &size, NULL, 0);
    if (err == -1) {
        goto end;
    }
    
    list = (struct kinfo_proc*)malloc(size);
    if (list == NULL) {
        goto end;
    }
    
    // then get the whole list
    err = sysctl( (int *) name, (sizeof(name) / sizeof(*name)) - 1, list, &size, NULL, 0);
    if (err == -1) {
        goto end;
    }
    count = size / sizeof(struct kinfo_proc);
    
    processes = [NSMutableArray arrayWithCapacity:(int)count];
    for (int i = 0; i < count; i++) {
        struct kinfo_proc *process = list + i;
        struct passwd *user = getpwuid(process->kp_eproc.e_ucred.cr_uid);
        NSMutableDictionary *entry = [NSMutableDictionary dictionaryWithCapacity:4];
        NSNumber *processID = [NSNumber numberWithInt:process->kp_proc.p_pid];
        NSString *processName = getProcessPath(process->kp_proc.p_pid);

        if (processID) {
            [entry setObject:processID forKey:@"processID"];
        }
        if (processName) {
            [entry setObject:processName forKey:@"processName"];
        }

        if (user){
            NSNumber *userID = [NSNumber numberWithUnsignedInt:process->kp_eproc.e_ucred.cr_uid];
            NSString *userName = [NSString stringWithFormat: @"%s",user->pw_name];

            if (userID) {
                [entry setObject:userID forKey:@"userID"];
            }
            if (userName) {
                [entry setObject:userName forKey:@"userName"];
            }
        }

        [processes addObject:[NSDictionary dictionaryWithDictionary:entry]];
    }
    
    ret = [NSArray arrayWithArray:processes];
end:
    if (list) {
        free(list);
    }
    return ret;
}

pid_t isProcessRunning(NSString *process)
{
    int ret = 0;
    NSArray *processes = getProcessList();
    for (NSDictionary *entry in processes) {
        if ([[[entry objectForKey:@"processName"] lastPathComponent] isEqualToString:process]) {
            ret = [entry[@"processID"] intValue];
            break;
        }
    }
    return ret;
}
typedef pid_t (*pidResolver)(pid_t pid);
BOOL isChildOfPID(pid_t target, pid_t root)
{
    if (target == 0 && root != 0) {
        return NO;
    } else if (target == 1 && root != 1) {
        return NO;
    } else if (target == root) {
        return YES;
    }

    struct proc_bsdinfo procInfo;
    proc_pidinfo(target, PROC_PIDTBSDINFO, 0, &procInfo, sizeof(procInfo));
    pid_t ppid = procInfo.pbi_ppid;
    if (ppid == root) {
        return YES;
    } else if (ppid == target) {
        return NO;
    } else if (ppid < 0) {
        return NO;
    }
    
    if ((ppid == 1) || (ppid == 0)) {
        pidResolver resolver = dlsym(RTLD_NEXT, "responsibility_get_pid_responsible_for_pid");
        pid_t respPid = resolver(target);
        if (respPid != -1) {
            ppid = respPid;
            if (ppid == target) {
                return NO;
            }
        }
    }
    return isChildOfPID(ppid, root);
}
@implementation ViewController
-(pid_t)ParentPidOf:(pid_t)target
{
    struct proc_bsdinfo procInfo;
    proc_pidinfo(target, PROC_PIDTBSDINFO, 0, &procInfo, sizeof(procInfo));
    return procInfo.pbi_ppid;
}
- (void)viewDidLoad {
    [super viewDidLoad];
//    return;
//    [self execute];
//    kAXTrustedCheckOptionPrompt

    CFStringRef keys[] = {kAXTrustedCheckOptionPrompt};
    CFBooleanRef values[] = {kCFBooleanTrue};

    //keyCallBacks：字典键值的回调，系统预设值kCFTypeDictionaryKeyCallBacks适用于所有CFTypes类型；当KEY是可变类型时，需要保存一个不可变的副本，需要使用kCFCopyStringDictionaryKeyCallBacks；
    //valueCallBacks:系统预设值kCFTypeDictionaryValueCallBacks适用于所有CFTypes类型
    CFDictionaryRef dic = CFDictionaryCreate(CFAllocatorGetDefault(), (const void**)keys, (const void**)values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
//    AXErrorfjldsajlkfsva
    BOOL ret = AXIsProcessTrustedWithOptions(dic);
    if (ret) {
        NSLog(@"====");
    }else {
        NSLog(@"=0000==");
    }
    NSTextField *text = [NSTextField textFieldWithString:@"fjldsajlkfsa"];
    [self.view addSubview:text];
    text.frame = NSMakeRect(0, 0, 100, 50);
    // Do any additional setup after loading the view.
}
- (void)mouseDown:(NSEvent *)event {
    [super mouseDown:event];
    PostKeyboardEvent(kVK_ANSI_Q,YES,kCGEventFlagMaskCommand);
    
//    [self execute];
//    pid_t pid = isProcessRunning(@"taijiperimeter");
//    pid_t ret = [self ParentPidOf:10328];
//    NSString *processPath = getProcessPath(10328);
//    NSLog(@"pid==:%d parent:%d path:%@",pid,ret,processPath);
//    PostKeyboardEvent(kVK_ANSI_Q,NO,kCGEventFlagMaskCommand);
}
- (void)execute {
  CGEventSourceRef src =
    CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
    
//  CGEventRef cmdd = CGEventCreateKeyboardEvent(src, kVK_Shift, true);
//  CGEventRef cmdu = CGEventCreateKeyboardEvent(src, kVK_Shift, false);
//  CGEventRef spcd = CGEventCreateKeyboardEvent(src, kVK_Space, true);
//  CGEventRef spcu = CGEventCreateKeyboardEvent(src, kVK_Space, false);
    CGEventTapLocation loc = kCGSessionEventTap; // kCGSessionEventTap also works

    CGKeyCode inputKeyCode = kVK_ANSI_C;
    CGEventRef copyCommandDown = CGEventCreateKeyboardEvent(nil, inputKeyCode, YES);
    CGEventSetFlags(copyCommandDown, kCGEventFlagMaskCommand);
    CGEventPost(loc, copyCommandDown);

    CGEventRef copyCommandup = CGEventCreateKeyboardEvent(nil, inputKeyCode, NO);
    CGEventSetFlags(copyCommandup, kCGEventFlagMaskCommand);
    CGEventPost(loc, copyCommandup);

//  CGEventPost(loc, cmdd);
//  CGEventPost(loc, spcd);
//  CGEventPost(loc, spcu);
//  CGEventPost(loc, cmdu);

//  CFRelease(cmdd);
//  CFRelease(cmdu);
//  CFRelease(spcd);
//  CFRelease(spcu);
  CFRelease(src);
}
void PostKeyboardEvent(CGKeyCode virtualKey, bool keyDown, CGEventFlags flags)
{
    CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateHIDSystemState);
    CGEventTapLocation loc = kCGHIDEventTap; // kCGSessionEventTap also works

    CGKeyCode inputKeyCode = kVK_ANSI_C;
    CGEventRef copyCommandDown = CGEventCreateKeyboardEvent(source, inputKeyCode, YES);
    CGEventSetFlags(copyCommandDown, kCGEventFlagMaskCommand);
    CGEventPost(loc, copyCommandDown);

    CGEventRef copyCommandup = CGEventCreateKeyboardEvent(source, inputKeyCode, NO);
    CGEventSetFlags(copyCommandup, kCGEventFlagMaskCommand);
    CGEventPost(loc, copyCommandup);
    //    CGKeyCode inputKeyCode = kVK_ANSI_C;
    
//    CGKeyCode inputKeyCode = kVK_ANSI_C;
//    CGEventRef saveCommandDown = CGEventCreateKeyboardEvent(nil, inputKeyCode, YES);
//    CGEventSetFlags(saveCommandDown, kCGEventFlagMaskCommand);
//    CGEventPost(kCGSessionEventTap, saveCommandDown);
//copyCommandup
//    CGEventRef saveCommandUp = CGEventCreateKeyboardEvent(nil, inputKeyCode, NO);
//fjldsajlkfsa
//    CGEventPost(kCGSessionEventTap, saveCommandUp);
//
    CFRelease(copyCommandDown);
    CFRelease(copyCommandup);
    CFRelease(source);
//    NSString * str = [[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString];
//    NSLog(@"strr:%@",str);
//    if (str.length > 10) {
//        str = [str substringToIndex:10];
//    }
//    [[NSPasteboard generalPasteboard] setString:str forType:NSPasteboardTypeString];
//    NSString * str1 = [[NSPasteboard generalPasteboard] stringForType:NSPasteboardTypeString];
//    NSLog(@"====%@",str1);
//    CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStatePrivate);
//    CGEventRef push = CGEventCreateKeyboardEvent(source, virtualKey, keyDown);
//    CGEventSetFlags(push, flags);
//    CGEventPost(kCGHIDEventTap, push);
//    CGEventPost(kCGSessionEventTap, saveCommandDown);
//    generalPasteboard
//    CFRelease(push);
//    CFRelease(source);fjldsajlkfsa
}
//CGKeyCode inputKeyCode = kVK_ANSI_S;
//CGEventSourceRef source = CGEventSourceCreate(kCGEventSourceStateCombinedSessionState);
//CGEventRef saveCommandDown = CGEventCreateKeyboardEvent(source, inputKeyCode, YES);
//CGEventSetFlags(saveCommandDown, kCGEventFlagMaskCommand);
//CGEventRef saveCommandUp = CGEventCreateKeyboardEvent(source, inputKeyCode, NO);
//
//CGEventPost(kCGAnnotatedSessionEventTap, saveCommandDown);
//CGEventPost(kCGAnnotatedSessionEventTap, saveCommandUp);
//
//CFRelease(saveCommandUp);
//CFRelease(saveCommandDown);
//CFRelease(source);
- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];

    // Update the view, if already loaded.
}


@end
